package org.xxpay.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.xxpay.core.common.constant.MchConstant;
import org.xxpay.core.common.constant.RetEnum;
import org.xxpay.core.common.exception.ServiceException;
import org.xxpay.core.common.util.MyLog;
import org.xxpay.core.common.util.MySeq;
import org.xxpay.core.common.util.XXPayUtil;
import org.xxpay.core.entity.*;
import org.xxpay.core.service.IAgentAccountService;
import org.xxpay.service.dao.mapper.AgentAccountHistoryMapper;
import org.xxpay.service.dao.mapper.AgentAccountMapper;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * @author: dingzhiwei
 * @date: 2018/4/29
 * @description:
 */
@Service
public class AgentAccountServiceImpl implements IAgentAccountService {

    @Autowired
    private AgentAccountMapper agentAccountMapper;

    @Autowired
    private AgentAccountHistoryMapper agentAccountHistoryMapper;

    private static final MyLog _log = MyLog.getLog(AgentAccountServiceImpl.class);

    @Override
    public List<AgentAccount> listAll(int offset, int limit) {
        AgentAccountExample example = new AgentAccountExample();
        example.setOrderByClause("createTime asc");
        example.setLimit(limit);
        example.setOffset(offset);
        return agentAccountMapper.selectByExample(example);
    }


    @Override
    public AgentAccount findByAgentId(Long agentId) {
        return agentAccountMapper.selectByPrimaryKey(agentId);
    }

    /**
     * 查找可用账户(代理商账户存在且状态正常)
     * @param agentId
     * @return
     */
    private AgentAccount findAvailableAccount(Long agentId) {
        AgentAccount agentAccount = findByAgentId(agentId);
        if(agentAccount == null || agentAccount.getStatus() != MchConstant.PUB_YES) {
            // 账户不存在
            throw ServiceException.build(RetEnum.RET_AGENT_ACCOUNT_NOT_EXIST);
        }
        return agentAccount;
    }

    @Override
    public BigDecimal sumAgentBalance(AgentAccount record) {
        AgentAccountExample exa = new AgentAccountExample();
        AgentAccountExample.Criteria c = exa.createCriteria();
        if(record!= null && record.getAgentId() != null){
            c.andAgentIdEqualTo(record.getAgentId());
        }
        return agentAccountMapper.sumAgentBalance(exa);
    }

    @Override
    public BigDecimal sumBalanceByParentAgentId(AgentInfo agentInfo) {
        return agentAccountMapper.sumBalanceByParentAgentId(agentInfo);
    }

    @Override
    public Map agentCountBalance() {
        return agentAccountMapper.agentCountBalance();
    }


    @Override
    public void resetTodayAmount() {
        AgentAccount updateRecord = new AgentAccount();
        updateRecord.setTodayIncome(0L);
        updateRecord.setTodayExpend(0L);
        this.agentAccountMapper.updateByExampleSelective(updateRecord, new AgentAccountExample());
    }

// ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓更改商户账户余额（ 采用事务行锁机制 ） ↓↓↓↓↓↓↓↓

    @Override
    @Transactional(transactionManager = "transactionManager", rollbackFor = Exception.class)
    public AgentAccount updateBalanceAndSafeKey(AgentAccount updateAccount) {

        AgentAccount dbAccount = agentAccountMapper.selectByPrimaryKey(updateAccount.getAgentId());
        if(!XXPayUtil.genAccountSafeKey(dbAccount).equals(dbAccount.getSafeKey())){
            _log.warn("[账户安全锁]代理账户安全锁校验失败,agentId={}", updateAccount.getAgentId());
            throw new ServiceException(RetEnum.RET_SERVICE_ACCOUNT_SAFE_ERROR); //安全机制码校验失败，无法继续操作
        }

        //判断是否更新成功
        if(agentAccountMapper.updateBalanceByAgentId(updateAccount) <= 0){
            throw new ServiceException(RetEnum.RET_SERVICE_AGENT_BALANCE_WRONG); //更新失败，触发事物回滚机制
        }
        dbAccount = agentAccountMapper.selectByPrimaryKey(updateAccount.getAgentId()); //数据库最新数据，与更新操作在同一事务下，查询的数据为当前更新数据
        if(dbAccount.getBalance() < 0 || dbAccount.getUnBalance() < 0 || dbAccount.getSecurityMoney() < 0
                || dbAccount.getSettAmount() < 0 || dbAccount.getAvailableBalance() < 0 || dbAccount.getAvailableSettAmount() < 0) {
            throw new ServiceException(RetEnum.RET_SERVICE_AGENT_BALANCE_WRONG); //数据有误，触发事物回滚机制
        }
        agentAccountMapper.updateSafeKey(updateAccount.getAgentId(), MchConstant.ACCOUNT_SAFE_SIGN_PWD); //更新safeKey
        return dbAccount;
    }

    @Override
    @Transactional(transactionManager = "transactionManager", rollbackFor = Exception.class)
    public void changeBalanceAndInsertHistory(SettRecord settRecord) {

        Long agentId = settRecord.getInfoId();
        Long settAmount = settRecord.getSettAmount();
        Long settFee = settRecord.getSettFee();
        Long agentChangeAmount = (0 - settAmount - settFee); //代理商变更金额

        //更新载体
        AgentAccount updateAgentAccount = new AgentAccount();

        updateAgentAccount.setAgentId(agentId);
        updateAgentAccount.setTodayExpend(Math.abs(agentChangeAmount));
        updateAgentAccount.setTotalExpend(Math.abs(agentChangeAmount));
        updateAgentAccount.setBalance(agentChangeAmount);
        updateAgentAccount.setUnBalance(agentChangeAmount);
        updateAgentAccount.setSettAmount(agentChangeAmount);

        AgentAccount dbAccount = updateBalanceAndSafeKey(updateAgentAccount); //更新并返回最新账户记录

        // 记录资金流水
        AgentAccountHistory agentAccountHistory = new AgentAccountHistory();
        agentAccountHistory.setAgentId(agentId);
        agentAccountHistory.setAmount(Math.abs(agentChangeAmount));

        agentAccountHistory.setAfterBalance(dbAccount.getBalance());
        agentAccountHistory.setBalance(agentAccountHistory.getAfterBalance() - agentChangeAmount);  //更新前的账户余额
        agentAccountHistory.setBizType(MchConstant.BIZ_TYPE_REMIT);
        agentAccountHistory.setFundDirection(MchConstant.FUND_DIRECTION_SUB);
        agentAccountHistory.setOrderId(settRecord.getSettOrderId());

        agentAccountHistoryMapper.insertSelective(agentAccountHistory);

    }

    @Override
    @Transactional(transactionManager = "transactionManager", rollbackFor = Exception.class)
    public void changeBalanceAndInsertHistory(Long agentId, Long changeAmount, Byte bizType, String bizItem, String orderId, String remark) {

        if(changeAmount == 0) return ; //更改金额为0, 不新增资金流水表, 无意义

        //1. update
        AgentAccount updateAgentAccount = new AgentAccount();
        updateAgentAccount.setAgentId(agentId);
        updateAgentAccount.setBalance(changeAmount);
        updateAgentAccount.setSettAmount(changeAmount);
        if(changeAmount > 0){ //总收益  & 今日收益
            updateAgentAccount.setTodayIncome(Math.abs(changeAmount));
            updateAgentAccount.setTotalIncome(Math.abs(changeAmount));
        }else { //总支出 & 今日支出
            updateAgentAccount.setTodayExpend(Math.abs(changeAmount));
            updateAgentAccount.setTotalExpend(Math.abs(changeAmount));
        }

        AgentAccount dbAccount = updateBalanceAndSafeKey(updateAgentAccount); //更新并返回最新账户记录

        //2. 记录资金流水
        AgentAccountHistory agentAccountHistory = new AgentAccountHistory();
        agentAccountHistory.setAgentId(agentId);
        agentAccountHistory.setAmount(Math.abs(changeAmount)); //取绝对值
        agentAccountHistory.setFundDirection(changeAmount > 0 ? MchConstant.FUND_DIRECTION_ADD : MchConstant.FUND_DIRECTION_SUB);

        agentAccountHistory.setBizType(bizType);
        agentAccountHistory.setBizItem(bizItem);
        agentAccountHistory.setOrderId(orderId);
        agentAccountHistory.setRemark(remark);

        agentAccountHistory.setAfterBalance(dbAccount.getBalance());
        agentAccountHistory.setBalance(dbAccount.getBalance() - changeAmount);
        agentAccountHistoryMapper.insertSelective(agentAccountHistory);

    }

    @Override
    @Transactional(transactionManager = "transactionManager", rollbackFor = Exception.class)
    public void changeBalanceAndInsertHistoryByPlat(Long agentId, Long changeAmount, String remark) {
        changeBalanceAndInsertHistory(agentId, changeAmount, MchConstant.AGENT_BIZ_TYPE_CHANGE_BALANCE, MchConstant.BIZ_ITEM_BALANCE, MySeq.getChangeAccount(), remark);
    }

    @Override
    @Transactional(transactionManager = "transactionManager", rollbackFor = Exception.class)
    public void onlyChangeUnBalance(Long agentId, Long changeUnBalance) {

        AgentAccount updateAgentAccount = new AgentAccount();
        updateAgentAccount.setAgentId(agentId);
        updateAgentAccount.setUnBalance(changeUnBalance);

        updateBalanceAndSafeKey(updateAgentAccount); //更新并返回最新账户记录
    }

// ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑


}
